package com.novunda.platform.security;

import com.novunda.platform.common.context.SpringContextHolder;
import com.novunda.platform.common.security.Encodes;
import com.novunda.platform.common.security.Principal;
import com.novunda.platform.common.utils.UserUtils;
import com.novunda.platform.entities.Menu;
import com.novunda.platform.entities.Role;
import com.novunda.platform.entities.User;
import com.novunda.platform.services.PlatformService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.List;

/**
 * @author linfeng
 * @since 2016/9/21.
 */
public abstract class CommonAuthorizingRealm extends AuthorizingRealm {

    private PlatformService platformService;

    /**
     * 清空用户关联权限认证，待下次使用时重新加载
     *
     * @param principal principal
     */
    public void clearCachedAuthorizationInfo(String principal) {
        SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
        clearCachedAuthorizationInfo(principals);
    }

    /**
     * 清空所有关联认证
     */
    public void clearAllCachedAuthorizationInfo() {
        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
        if (cache != null) {
            for (Object key : cache.keys()) {
                cache.remove(key);
            }
        }
    }

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
     *
     * @param principals PrincipalCollection
     * @return AuthorizationInfo
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        Principal principal = (Principal) getAvailablePrincipal(principals);
        User user = getPlatformService().getUserByLoginName(principal.getUsername());
        if (user != null) {
            UserUtils.putCache("user", user);
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

            List<Role> roleList = user.getRoleList();
            for (Role role : roleList) {
                if (StringUtils.isNotBlank(role.getEnname())) {
                    info.addRole(role.getEnname());
                }
            }

            List<Menu> list = UserUtils.getMenuList();
            for (Menu menu : list) {
                if (StringUtils.isNotBlank(menu.getPermission())) {
                    // 添加基于Permission的权限信息
                    info.addStringPermission(menu.getPermission());
                }
            }
            return info;
        } else {
            return null;
        }


    }

    /**
     * 认证回调函数, 登录时调用
     *
     * @param authenticationToken {@link AuthenticationToken}
     * @return AuthenticationInfo
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        SecurityUtils.getSubject();
        User user = getPlatformService().getUserByLoginName(token.getUsername());
        if (user != null) {
            byte[] salt = Encodes.decodeHex(user.getPassword().substring(0, 16));
            return new SimpleAuthenticationInfo(new Principal(user),
                    user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
        } else {
            return null;
        }

    }

    /**
     * 获取系统业务对象
     */
    public PlatformService getPlatformService() {
        if (platformService == null) {
            platformService = SpringContextHolder.getBean(PlatformService.class);
        }
        return platformService;
    }

}
